#include "Resource.h"
#include "String.h"
#include "SharedPtr.h"
#include "ResourceManager.h"
#include "Database/DatabaseEnv.h"
#include "StringConverter.h"
#include "NGLog.h"
#include "Character.h"
#include "CharManager.h"
#include "WorldPacket.h"
#include "OpcodesEx.h"
#include "RegionManager.h"
#include "Users.h"
#include "UserManager.h"
#include "WSSocket.h"
#include "WSSocketManager.h"
#include "Message.h"
#include "MD5.h"
#include "AIInterface.h"
#include "VipCardManager.h"
#include "Tools.h"
#include "DataTransferManager.h"
#include "AIInterface.h"
#include "GameDefine.h"
#include LOG_MGR_PATH
#include LOGIC_MGR_PATH
#include PROTOCOLS_MGR_PATH
#include XMLDATA_MGR_PATH
#include ENUM_PATH

#define GAME_TYPE 10
using namespace AIScript;
//-------------------------------------------------------------------------
bool 	DataTransferManager::StartTransfer(UserPtr & pUser, const uint32 & key, const uint16 & gameid, const uint16 & cmdid, 
					const uint16 & orderType, const uint16 & modelid, const uint32 & number, const String & msg)
{
	if(pUser.isNull() || pUser->m_Socket.isNull())
		return false;
		
	WSSocketPtr pSocket = pUser->m_Socket.getResourcePtr();
	if(pSocket.isNull())
		return false;
	
	GameBank pBank;
	if(getTransfer(pUser, gameid, &pBank))
	{
		if(pBank.status != en_TransferStatusFree)
		{
			if(pBank.status == en_TransferStatusError)
			{
				clearTransfer(&pBank);
			}
			else			
				return false;
		}
		
		pBank.data1 = gameid;	// 指令KEY
		pBank.data5 = cmdid;	// 指令
		pBank.data6 = orderType;// 操作类型
		pBank.data7 = modelid;	// 操作物品
		pBank.data8 = number;	// 操作数量
		pBank.sdata1 = msg;		// 需要发送的消息
		pBank.login_pass = randomSign(pUser);
		
		if(updateTransferReq(&pBank))
		{
			WorldPacket newP;
			if(CreateTransferPacket(&newP, en_ServerType_Host, gameid, cmdid, pBank.login_pass))
				pSocket->SendPacket(&newP);
			return true;
		}		
	}
	
	return false;
}

//-------------------------------------------------------------------------
bool 	DataTransferManager::ThawyCommand(UserPtr & pUser)
{
	if(pUser.isNull() || pUser->m_Socket.isNull())
		return false;
		
	WSSocketPtr pSocket = pUser->m_Socket.getResourcePtr();
	if(pSocket.isNull())
		return false;
	
	GameBank pBank;
	if(getTransfer(pUser, en_SmallGameId_Morra, &pBank))
	{
		if(pBank.status != en_TransferStatusFree)
		{
			if(pBank.status == en_TransferStatusError)
			{
				clearTransfer(&pBank);
			}
			else			
				return false;
		}
		
		pBank.data1 = 0;	// 指令KEY
		pBank.data5 = 0;	// 指令
		pBank.data6 = en_OrderType_Thawy;// 操作类型
		pBank.data7 = 0;	// 操作物品
		pBank.data8 = 0;	// 操作数量
		pBank.login_pass = randomSign(pUser);
		if(updateTransferReq(&pBank))
		{
			WorldPacket newP;
			if(CreateTransferPacket(&newP, en_ServerType_Host, en_SmallGameId_Morra, 0, pBank.login_pass))
				pSocket->SendPacket(&newP);
			return true;
		}		
	}
	
	return true;
}

//-------------------------------------------------------------------------
bool 	DataTransferManager::RecevingTransfer(UserPtr & pUser, const uint16 & gameid, const uint16 & cmdid, const String & szSign)
{
	if(pUser.isNull() || pUser->m_Socket.isNull())
		return false;	
	
	GameBank pBank;
	if(getTransfer(pUser, gameid, &pBank))
	{
		if(pBank.login_pass != szSign || pBank.status != en_TransferStatusStart)
			return false;
		DisposeReceving(pUser, pBank);
	}
	return false;
}

//-------------------------------------------------------------------------
bool DataTransferManager::DisposeReceving(UserPtr &pUser, GameBank &pBank)
{	
	WSSocketPtr pSocket = pUser->m_Socket.getResourcePtr();
	if(pSocket.isNull())
		return false;
	uint16 gameid = pBank.data1;
	uint16 cmdid = pBank.data5;
	uint16 modelid = pBank.data7;			
	CharPtr pChr = sCharMgr.getByHandle(pUser->getUInt32Field("char_id"));
	if(pChr.isNull())
		return false;
	
	AICreatureBaseInterface *pAiChrInfe = TO_CREATURE_BASE_INTERFACE(pChr->getAIInterface());
	if (!pAiChrInfe)
		return false;
	if(!checkUserAuthority(pUser, gameid, cmdid))
		return false;
	if(!updateTransferStatus(&pBank, en_TransferStatusStart, en_TransferStatusReceving))
		return false;		
	WorldPacket newP;
	if(pBank.data6 & en_OrderType_Exchange)
	{
		uint32 excNum = pBank.data8;			
		if (modelid == ItemModel_Token)
		{// 乐币兑换积分
			if(!sGLMgr.reduceItemNum(pChr, modelid, excNum, !(pBank.data6 & en_OrderType_Sneak)))
			{
				if(CreateTransferResultPacket(&newP, gameid, cmdid, 1))
					pSocket->SendPacket(&newP);					
				clearTransfer(&pBank);
				return false;
			}
			sLogDataMgr.UpdateItemsInfoLog(pChr, en_ST_NormalExchange, ItemModel_Token, en_UNT_Reduce, pBank.data8, gameid);
			uint32 addNum = excNum * 10;	// 乐币和积分兑换比例为1:10
			sGLMgr.addItemNum(pChr, ItemModel_Score, addNum, !(pBank.data6 & en_OrderType_Sneak));
			sLogDataMgr.UpdateItemsInfoLog(pChr, en_ST_NormalExchange, ItemModel_Score, en_UNT_Add, pBank.data8, gameid);
		}
		else if (modelid == ItemModel_Score)
		{// 积分兑换铜钱
			if(!sGLMgr.reduceItemNum(pChr, modelid, excNum, !(pBank.data6 & en_OrderType_Sneak)))
			{
				if(CreateTransferResultPacket(&newP, gameid, cmdid, 1))
					pSocket->SendPacket(&newP);					
				clearTransfer(&pBank);
				return false;
			}
			sLogDataMgr.UpdateItemsInfoLog(pChr, en_ST_NormalExchange, ItemModel_Score, en_UNT_Reduce, pBank.data8, gameid);
			uint32 addNum = excNum * 1000;	// 乐币和积分兑换比例为1:10
			sGLMgr.addItemNum(pChr, ItemModel_Coins, addNum, !(pBank.data6 & en_OrderType_Sneak));
			sLogDataMgr.UpdateItemsInfoLog(pChr, en_ST_NormalExchange, ItemModel_Coins, en_UNT_Add, pBank.data8, gameid);
		}
		else
		{
			if(CreateTransferResultPacket(&newP, gameid, cmdid, 1))
				pSocket->SendPacket(&newP);					
			clearTransfer(&pBank);
			return false;
		}
	}
	else if(pBank.data6 & en_OrderType_Thawy)
	{// 解除冻结
		if(modelid)
		{
			UnchainItemNum(pUser, modelid);
		}
		else
		{
			UnchainAllItem(pUser);
			clearTransfer(&pBank);
			return true;
		}
	}
	if(pBank.data6 & en_OrderType_Add)
	{// 增加
		uint32 number = pBank.data8;
		if (modelid < ItemModel_Coins)
		{// 增加虚拟卡
			VIPCard vCard = sVipCardMgr.GetVipCard(modelid);
			if (vCard.isNull())
				return false;
			vCard.coins *= number;
			vCard.money *= number;
			vCard.days *= number;
			vCard.morraNum *= number;
			pAiChrInfe->AddNewVIPInfo(vCard);
			// 需要加的铜钱
			modelid = ItemModel_Coins;
			number = vCard.coins;
		}
		
		sGLMgr.addItemNum(pChr, modelid, number, !(pBank.data6 & en_OrderType_Sneak));
		sLogDataMgr.UpdateItemsInfoLog(pChr, en_ST_SMGame, modelid, en_UNT_Add, pBank.data8, gameid, cmdid);	
	}
	else if(pBank.data6 & en_OrderType_Reduce)
	{// 减少
		if(!sGLMgr.reduceItemNum(pChr, modelid, pBank.data8, !(pBank.data6 & en_OrderType_Sneak)))
		{
			if(CreateTransferResultPacket(&newP, gameid, cmdid, 1))
				pSocket->SendPacket(&newP);
				
			clearTransfer(&pBank);
			return false;
		}
		sLogDataMgr.UpdateItemsInfoLog(pChr, en_ST_SMGame, modelid, en_UNT_Reduce, pBank.data8, gameid, cmdid);	
	}
	else if(pBank.data6 & en_OrderType_Congeal)
	{// 扣除冻结
		if(!CongealItemNum(pUser, modelid, pBank.data8))
		{
			if(CreateTransferResultPacket(&newP, gameid, cmdid, 1))
				pSocket->SendPacket(&newP);
				
			clearTransfer(&pBank);
			return false;
		}			
	}
	if (pBank.sdata1 != "")
	{// 需要发送消息
		sGLMgr.SendNotice(pBank.sdata1);
	}
	
	pBank.sdata1 = "";
	// 验证数量
	uint32 number = sGLMgr.GetItemNum(pChr, modelid);
	if(pBank.data6 & en_OrderType_Validate)
	{
		if(number < (uint32)pBank.data8)
		{
			if(CreateTransferResultPacket(&newP, gameid, cmdid, 1))
				pSocket->SendPacket(&newP);
				
			clearTransfer(&pBank);
			return true;
		}
	}
	if(pBank.data6 & en_OrderType_Void)
	{// 不作返回
		clearTransfer(&pBank);
		return true;
	}		
	
	if(modelid == ItemModel_Coins)
	{
		pBank.coins = number;
	}
	else if(modelid == ItemModel_March)
	{
		pBank.march = number;
	}
	
	XMLDataSet vipXml;
	if(sVipCardMgr.GetVipXmlData(pChr, vipXml))
	{// VIP相关数据
		pBank.user_data = vipXml.getXML();
	}
	
	pBank.login_pass = randomSign(pUser);
	if(updateTransferReport(&pBank))
	{			
		if(CreateTransferPacket(&newP, en_ServerType_Subgame, gameid, cmdid, pBank.login_pass))
			pSocket->SendPacket(&newP);			
		return true;
	}
	return true;
}
//-------------------------------------------------------------------------
bool 	DataTransferManager::ValidateTransfer(UserPtr & pUser, const uint16 & gameid, const uint16 & cmdid, const String & szSign)
{
using namespace AIScript;
	if(pUser.isNull() || pUser->m_Socket.isNull())
		return false;
	GameBank pBank;
	if(!getTransfer(pUser, gameid, &pBank))
		return false;
	
	if(pBank.login_pass != szSign)
	{
		clearTransfer(&pBank);
		Log.Error("DataTransferManager Test","gameid[%u,%u] pUser[%s] BankID[%u] BankStatus[%u]", 
					gameid, cmdid, pUser->getStringField("name").c_str(), pBank.bank_id, pBank.status);
		return false;
	}
	return DisposeValidate(pUser, pBank);	
}
//-------------------------------------------------------------------------
bool DataTransferManager::DisposeValidate(UserPtr &pUser, GameBank &pBank)
{	
	CharPtr pChr = sCharMgr.getByHandle(pUser->getUInt32Field("char_id"));
	if(pChr.isNull())
		return false;
	
	uint16 gameid = pBank.data1;
	uint16 cmdid = pBank.data5;
	// 修改状态
	if(!updateTransferStatus(&pBank, en_TransferStatusReport, en_TransferStatusWorking))
	{
		clearTransfer(&pBank);
		Log.Error("DataTransferManager Test","gameid[%u,%u] pUser[%s] BankID[%u] BankStatus[%u]", 
					gameid, cmdid, pUser->getStringField("name").c_str(), pBank.bank_id, pBank.status);
		return false;
	}
	
	pChr->setUInt32Field("speed", pBank.coins);
	pChr->setUInt32Field("speed_org", pBank.march);
	
	XMLDataSet vipXml;
	vipXml.Load(pBank.user_data);
	sVipCardMgr.SetVipXmlData(pChr, vipXml);
	
	clearTransfer(&pBank);
	AICreatureBaseInterface *pAiChrInfe = TO_CREATURE_BASE_INTERFACE(pChr->getAIInterface());
	if(pAiChrInfe)
	{
		if(!pAiChrInfe->RunGame(pBank.data1))
		{
			WSSocketPtr pSocket = pUser->m_Socket.getResourcePtr();
			if(pSocket.isNull())
				return false;
			WorldPacket newP;
			if(CreateTransferResultPacket(&newP, gameid, cmdid, 1))
				pSocket->SendPacket(&newP);					
		}
		else
		{
			return true;
		}
	}
	return false;
}
//-------------------------------------------------------------------------
void 	DataTransferManager::ResetRecevingData(UserPtr &pUser)
{
	if (pUser.isNull())
		return;
	CharPtr pChr = sCharMgr.getByHandle(pUser->getUInt32Field("char_id"));
	if (pChr.isNull())
		return;
	
	// if (!sChannelMgr.getBankDBCount("`platform_id` = %u and `type` = %u and status = %u", 
				// pUser->getUInt32Field("platform_id"), GAME_TYPE, en_TransferStatusStart))
		// return;
	
	std::list<GameBank> lstBanks;
	if (sChannelMgr.getBankList(&lstBanks, 0, 1, "`platform_id` = %u and `type` = %u and status = %u", 
				pUser->getUInt32Field("platform_id"), GAME_TYPE, en_TransferStatusStart))
	{
		std::list<GameBank>::iterator iter, enditer = lstBanks.end();
		for (iter = lstBanks.begin(); iter != enditer; ++ iter)
		{
			DisposeReceving(pUser, *iter);
		}
	}
}
//-------------------------------------------------------------------------
void 	DataTransferManager::ResetWorkingData(UserPtr &pUser)
{
	if (pUser.isNull())
		return;
	CharPtr pChr = sCharMgr.getByHandle(pUser->getUInt32Field("char_id"));
	if (pChr.isNull())
		return;
	// if (!sChannelMgr.getBankDBCount("`platform_id` = %u and `type` = %u and status = %u", 
				// pUser->getUInt32Field("platform_id"), GAME_TYPE, en_TransferStatusReport))
		// return;
	
	std::list<GameBank> lstBanks;
	if (sChannelMgr.getBankList(&lstBanks, 0, 1, "`platform_id` = %u and `type` = %u and status = %u", 
				pUser->getUInt32Field("platform_id"), GAME_TYPE, en_TransferStatusReport))
	{
		std::list<GameBank>::iterator iter, enditer = lstBanks.end();
		for (iter = lstBanks.begin(); iter != enditer; ++ iter)
		{
			DisposeValidate(pUser, *iter);
		}
	}	
}

//-------------------------------------------------------------------------
bool 	DataTransferManager::clearTransfer(UserPtr & pUser)
{
	if (pUser.isNull())
		return false;
	
	return CenterDatabase.WaitExecute("update game_bank set `coins`= 0,`march`=0,`prize`=0,`login_pass`='',`status`=%u,`last_time` = %u, \
					`data1`=0,`data5`=0,`data6`=0,`data7`=0,`data8`=0,`user_data`='' where `platform_id`=%u AND `type`=%u AND `status`<>%u", 
					en_TransferStatusFree, time(0), pUser->getUInt32Field("platform_id"), GAME_TYPE, en_TransferStatusFree);
}

//-------------------------------------------------------------------------
bool DataTransferManager::createTransfer(UserPtr & pUser, const uint32 & gameid, GameBank * pGameBank)
{
	if (pUser.isNull() || !pUser->getUInt32Field("platform_id") || !gameid)
		return false;
		
	uint64 bankid = 0;
	if (!sChannelMgr.getBankDBCount("`platform_id` = %u and `type` = %u and `game_id` = %u", 
		pUser->getUInt32Field("platform_id"), GAME_TYPE, gameid))
	{
		GameBank *pBank = sChannelMgr.newDumyBank();
		if (pBank)
		{
			pBank->platform_id = pUser->getUInt32Field("platform_id");
			pBank->gz_id = pUser->getUInt32Field("gz_id");
			pBank->game_id = gameid;
			pBank->type = GAME_TYPE;
			pBank->status = en_TransferStatusFree;
			pBank->uid = pUser->getHandle();
			pBank->name = pUser->getStringField("name");
			pBank->nick = pUser->getStringField("nick");
		
			bankid = sChannelMgr.addBankDB(pBank);
			
			if(pGameBank != NULL)
			{
				*pGameBank = *pBank;
				pGameBank->bank_id = bankid;
			}
		}
		
		sChannelMgr.freeDumyBank(pBank);
	}
	
	return true;
}

bool DataTransferManager::updateTransferError(GameBank * pBank)
{
	return CenterDatabase.WaitExecute("update game_bank set `status`=%u, `last_time`=%u where `bank_id`=%u", 
								en_TransferStatusError, time(0), pBank->bank_id);
}

//-------------------------------------------------------------------------
bool DataTransferManager::getTransfer(UserPtr & pUser, const uint32 & gameid, GameBank * pBank)
{
	if(pUser.isNull())
		return false;
	
	std::list<GameBank> lstBanks;
	if (!sChannelMgr.getBankList(&lstBanks, 0, 1, "`platform_id` = %u and `type` = %u and game_id = %u", 
				pUser->getUInt32Field("platform_id"), GAME_TYPE, gameid))
	{
		if(!createTransfer(pUser, gameid, pBank))
			return false;
	}
	else
	{
		*pBank = lstBanks.front();
	}
	
	return true;
}

//-------------------------------------------------------------------------
bool DataTransferManager::updateTransferReq(GameBank * pBank)
{
	return CenterDatabase.WaitExecute("update game_bank set `login_pass`='%s',`status`=%u, 	`last_time`=%u,\
								`data1`=%u,`data5`=%u,`data6`=%u,`data7`=%u,`data8`=%u, `sdata1`='%s' where `bank_id`=%u AND `status`=%u", 
								pBank->login_pass.c_str(), en_TransferStatusStart, time(0), 
								pBank->data1, pBank->data5, pBank->data6, pBank->data7, pBank->data8, pBank->sdata1.c_str(), pBank->bank_id, en_TransferStatusFree);
}

//-------------------------------------------------------------------------
bool DataTransferManager::updateTransferReport(GameBank * pBank)
{
	return CenterDatabase.WaitExecute("update game_bank set `login_pass`='%s',`status`=%u, 	`last_time`=%u,\
								`coins`=%u,`march`=%u,`user_data`='%s' where `bank_id`=%u AND `status`=%u", 
								pBank->login_pass.c_str(), en_TransferStatusReport, time(0), 
								pBank->coins, pBank->march, pBank->user_data.c_str(), pBank->bank_id, en_TransferStatusReceving);
}

//-------------------------------------------------------------------------
bool DataTransferManager::updateTransferStatus(GameBank * pBank, const uint8 & currStatus, const uint8 & nextStatus)
{
	return CenterDatabase.WaitExecute("update game_bank set `status`=%u, `last_time`=%u where `bank_id`=%u AND `status`=%u", 
								nextStatus, time(0), pBank->bank_id, currStatus);
}

//-------------------------------------------------------------------------
bool DataTransferManager::clearTransfer(GameBank * pBank)
{
	return CenterDatabase.WaitExecute("update game_bank set `coins`= 0,`march`=0,`prize`=0,`login_pass`='',`status`=%u,`last_time` = %u, \
					`data1`=0,`data5`=0,`data6`=0,`data7`=0,`data8`=0,`user_data`='' where `bank_id`=%u", 
					en_TransferStatusFree, time(0),pBank->bank_id);
}

//-------------------------------------------------------------------------
String DataTransferManager::randomSign(UserPtr & pUser)
{
	if(pUser.isNull())
		return "";
		
	char str[512];
	sprintf(str, "%s,%u,%u,%u", SMALLGAME_SIGN_CODE, pUser->getUInt32Field("platform_id"), RandomUInt(10000, 9999999), (uint32)time(0));
	CMD5 md5;	
	return md5.GenerateMD5(str);
}

//-------------------------------------------------------------------------
String DataTransferManager::getItemField(const uint16 & modelid)
{
	if(modelid == ItemModel_Coins)
	{
		return "coins";
	}
	else if(modelid == ItemModel_March)
	{
		return "march";
	}
	
	return "";
}

//-------------------------------------------------------------------------
bool 	DataTransferManager::CreateTransferPacket(WorldPacket * packet, const uint16 & target, 
									const uint16 & gameid, const uint16 & cmdid, const String & szSign)
{
	if(!packet)
		return false;
	packet->clear();
	// 预开辟空间
	packet->reserve(128);
	packet->SetOpcode(CMSG_GAME_ORDER);
	*packet << uint16(CMSG_GAME_ORDER) << uint16(0) << target << gameid << cmdid;
	AppendPacketString<uint8>(packet, szSign);
	// 设置包真正的长度
	packet->SetLength(packet->size());
	
	Log.Notice("DataTransferManager Test","CreateTransferPacket target[%u], gameid[%u] cmdid[%u] szSign[%s]", target, gameid, cmdid, szSign.c_str());
	return true;
}

//-------------------------------------------------------------------------
bool 	DataTransferManager::CreateTransferResultPacket(WorldPacket * packet, const uint16 & gameid, const uint16 & cmdid, const uint8 & re)
{
	if(!packet)
		return false;
	packet->clear();
	// 预开辟空间
	packet->reserve(128);
	packet->SetOpcode(SMSG_SGCOMMON_ORDER);
	*packet << uint16(SMSG_SGCOMMON_ORDER) << uint16(0) << gameid << cmdid << re;
	// 设置包真正的长度
	packet->SetLength(packet->size());
	return true;
}

//-------------------------------------------------------------------------
bool 	DataTransferManager::checkUserAuthority(UserPtr & pUser, const uint16 & gameid, const uint16 & cmdid)
{
	if(pUser.isNull())
		return false;
	
	CharPtr pChr = sCharMgr.getByHandle(pUser->getUInt32Field("char_id"));
	if(pChr.isNull())
		return false;
		
	if(gameid == en_SmallGameId_Morra)
	{// 猜拳有VIP限制	
		if(!sVipCardMgr.GetMorraLeftNum(pChr))
			return false;
		
		if(cmdid == 4)
		{// 产生结果
			return sVipCardMgr.Morra(pChr);
		}
	}
	
	return true;
}

//-------------------------------------------------------------------------
bool 	DataTransferManager::CongealItemNum(UserPtr & pUser, const uint16 & modelid, const uint32 & number)
{
// 只能冻结一份
	CharPtr pChr = sCharMgr.getByHandle(pUser->getUInt32Field("char_id"));
	if(pChr.isNull())
		return false;

	ItemPtr pItem = sGLMgr.GetItem(pChr, modelid);
	if(pItem.isNull())
		return false;
	
	pItem->setUInt32Field("num", pItem->getUInt32Field("hp") + pItem->getUInt32Field("num"));
	
	if(pItem->getUInt32Field("num") < number)
		return false;
	
	pItem->setUInt32Field("num", pItem->getUInt32Field("num") - number);
	pItem->setUInt32Field("hp", number);

	return true;
}

//-------------------------------------------------------------------------
bool	DataTransferManager::UnchainItemNum(UserPtr & pUser, const uint16 & modelid)
{
	CharPtr pChr = sCharMgr.getByHandle(pUser->getUInt32Field("char_id"));
	if(pChr.isNull())
		return false;
	
	ItemPtr pItem = sGLMgr.GetItem(pChr, modelid);
	if(pItem.isNull())
		return false;
	
	pItem->setUInt32Field("num", pItem->getUInt32Field("num") + pItem->getUInt32Field("hp"));

	return true;
}

//-------------------------------------------------------------------------
void 	DataTransferManager::UnchainAllItem(UserPtr & pUser)
{
	CharPtr pChr = sCharMgr.getByHandle(pUser->getUInt32Field("char_id"));
	if(pChr.isNull())
		return ;
		
	std::list<ItemPtr> items;
	pChr->getItemsList(&items);
	std::list<ItemPtr>::iterator ii, endii = items.end();
	for(ii = items.begin(); ii != endii; ++ ii)
	{
		(*ii)->setUInt32Field("num", (*ii)->getUInt32Field("hp") + (*ii)->getUInt32Field("num"));		
	}
}
	
